package main

import (
	"fmt"
	"github.com/go-redis/redis"
)

// 声明一个全局的redisDb变量
var client *redis.Client

// 根据redis配置初始化一个客户端
func initClient() (err error) {
	client = redis.NewClient(&redis.Options{
		Addr:     "61.160.96.204:5387", // redis地址
		Password: "chall123.",          // redis密码，没有则留空
		DB:       0,                    // 默认数据库，默认是0
	})

	//通过 *redis.Client.Ping() 来检查是否成功连接到了redis服务器
	_, err = client.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	err := initClient()
	if err != nil {
		//redis连接错误
		panic(err)
	}
	fmt.Println("Redis连接成功")
	RegularKeys()
	//HashKeys()
	//ListKeys()
	//SetKeys()
	//ZsetKeys()
}

func HashKeys() (err error) {
	err = client.HSet("golang", "version", "1111111").Err()
	if err != nil {
		panic(err)
	}

	value, err := client.HGet("golang", "version").Result()
	fmt.Println("version is:", value)

	fieldMap := make(map[string]interface{})
	fieldMap["path"] = "xxx/xxx/xxx"
	fieldMap["date"] = "2021-5-10"
	err = client.HMSet("golang", fieldMap).Err()
	if err != nil {
		panic(err)
	}
	values, err := client.HGetAll("golang").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("values are:", values)

	return
}

func RegularKeys() (err error) {

	err = client.Set("regular", "regular", 0).Err()
	if err != nil {
		panic(err)
	}
	err = client.Set("regular1", "regular1", 0).Err()
	if err != nil {
		panic(err)
	}

	value, err := client.Get("regular").Result()
	fmt.Println("value is: ", value)

	err = client.GetSet("regular", "regular1").Err()
	if err != nil {
		panic(err)
	}
	mvalue, err := client.MGet("regular", "regular1").Result()
	fmt.Println("values are: ", mvalue)

	//rds.Del("regular")
	return
}

func ListKeys() (err error) {

	err = client.LPush("pushkey", "data1", "data2", "data3").Err()
	if err != nil {
		panic(err)
	}
	values, err := client.LRange("pushkey", 0, -1).Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("values are:", values)
	err = client.RPush("pushkey", "data4").Err()
	if err != nil {
		panic(err)
	}
	values, err = client.LRange("pushkey", 0, -1).Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("values are:", values)

	err = client.LPop("pushkey").Err()
	if err != nil {
		panic(err)
	}
	values, err = client.LRange("pushkey", 0, -1).Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("values are:", values)

	err = client.RPop("pushkey").Err()
	if err != nil {
		panic(err)
	}
	values, err = client.LRange("pushkey", 0, -1).Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("values are:", values)
	err = client.LRem("pushkey", 0, "data1").Err()
	if err != nil {
		panic(err)
	}
	values, err = client.LRange("pushkey", 0, -1).Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("values are:", values)
	return
}

func SetKeys() (err error) {
	err = client.SAdd("setkey", 100, 200, 300).Err()
	size, err := client.SCard("setkey").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("size of set is:", size)

	members, err := client.SMembers("setkey").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("members are:", members)

	member := 1000
	result, err := client.SIsMember("setkey", member).Result()
	if err != nil {
		panic(err)
	}
	var flag string
	if !result {
		flag = "not "
	}
	fmt.Println(fmt.Sprintf("%d is %sa member of setkey", member, flag))

	// 集合操作
	client.SAdd("setkey1", 100, 200, 900, 2300).Err()

	res, _ := client.SInter("setkey", "setkey1").Result()
	fmt.Println("交集：", res)

	res, _ = client.SDiff("setkey1", "setkey").Result()
	fmt.Println("差集：", res)

	member1, _ := client.SPop("setkey1").Result()
	fmt.Println("setkey1删除：", member1)

	member2, _ := client.SPopN("setkey", 2).Result()
	fmt.Println("setkey删除：", member2)

	client.SMove("setkey", "setkey1", 100)
	members, _ = client.SMembers("setkey1").Result()
	fmt.Println("setkey移动：", members)

	client.Del("setkey")
	client.Del("setkey1")
	return
}

func ZsetKeys() (err error) {
	zsetKey := "language_rank"
	languages := []redis.Z{
		{Score: 90.0, Member: "Golang"},
		{Score: 98.0, Member: "Java"},
		{Score: 95.0, Member: "Python"},
		{Score: 97.0, Member: "JavaScript"},
		{Score: 92.0, Member: "C/C++"},
	}

	num, err := client.ZAdd(zsetKey, languages...).Result()
	if err != nil {
		fmt.Printf("zadd failed, err:%v\n", err)
		return
	}
	fmt.Printf("ZAdd添加成功 %d 元素\n", num)
	// 添加一个元素到集合
	client.ZAdd(zsetKey, redis.Z{Score: 87, Member: "Vue"}).Err()

	//给元素Vue加上8分，最终vue得分95分
	client.ZIncrBy(zsetKey, 8, "Vue")
	// 返回从0到-1位置的集合元素， 元素按分数从小到大排序 0到-1代表则返回全部数据
	values, err := client.ZRange(zsetKey, 0, -1).Result()
	if err != nil {
		panic(err)
	}
	for _, val := range values {
		fmt.Println(val)
	}

	//返回集合元素的个数
	size, err := client.ZCard(zsetKey).Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(size)

	//统计某个分数段内的元素个数，这里是查询的95<分数<100的元素个数
	count, err := client.ZCount(zsetKey, "95", "100").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(count)

	values, err = client.ZRange(zsetKey, 0, -1).Result()
	if err != nil {
		panic(err)
	}
	for _, val := range values {
		fmt.Println(val)
	}

	// 初始化查询条件， Offset和Count用于分页
	op := redis.ZRangeBy{
		Min:    "80",  // 最小分数
		Max:    "100", // 最大分数
		Offset: 0,     // 类似sql的limit, 表示开始偏移量
		Count:  5,     // 一次返回多少数据
	}
	//根据分数范围返回集合元素，元素根据分数从小到大排序，支持分页。
	values, err = client.ZRangeByScore(zsetKey, op).Result()
	if err != nil {
		panic(err)
	}
	for _, val := range values {
		fmt.Println(val)
	}

	score, _ := client.ZScore(zsetKey, "Golang").Result()
	fmt.Println(score)
	//根据元素名，查询集合元素在集合中的排名，从0开始算，集合元素按分数从小到大排序
	rk, _ := client.ZRank(zsetKey, "Java").Result()
	fmt.Println(rk)

	// 删除集合中的元素Java
	client.ZRem(zsetKey, "Java")

	// 删除集合中的元素Golang和Vue
	// 支持一次删除多个元素
	client.ZRem(zsetKey, "Golang", "Vue")

	//根据索引范围删除元素
	//集合元素按分数排序，从最低分到高分，删除第0个元素到第5个元素。
	// 这里相当于删除最低分的几个元素
	client.ZRemRangeByRank(zsetKey, 0, 5)

	// 位置参数写成负数，代表从高分开始删除。
	// 这个例子，删除最高分数的两个元素，-1代表最高分数的位置，-2第二高分，以此类推。
	client.ZRemRangeByRank(zsetKey, -1, -2)
	return
}
